#include <utility>

#define TWO(X) X X
#define FOUR(X) X X X X

void* alloc_hp();

bool try_alloc_hp(void *&buffer);

int free_hp(void* buffer);

void goto_cpu(size_t i);

void goto_cpu(pthread_attr_t &attr, size_t i);

void set_seed();

class addr_gen{
    public:
    virtual void* operator[](size_t i) const = 0;
    virtual size_t size() const = 0;
};

class order_gen{
    public:
    virtual size_t operator[](size_t i) const = 0;
};

class seq_addr: public addr_gen{
    void* base;
    size_t range, stride, offset;
    public:
    void* operator[](size_t i) const;
    size_t size() const;
    seq_addr(void* base, size_t range, size_t stride, size_t offset);
};

class mask_addr: public addr_gen{
    void* base;
    size_t mask, one;
    public:
    void* operator[](size_t i) const;
    size_t size() const;
    mask_addr(void* base, size_t mask, size_t one = 0);
};

class slice_addr: public addr_gen{
    public:
    addr_gen &base;
    order_gen &ord;
    size_t offset, len;
    void* operator[](size_t i) const {return base[ord[offset + i]];}
    size_t size() const {return len;}
    slice_addr(addr_gen &gen, order_gen &ord, size_t len = 0, size_t offset = 0):base(gen),ord(ord) {this->len=len;this->offset=offset;}
};

class mix_addr: public addr_gen{
    addr_gen **generators;
    public:
    void* operator[](size_t i) const;
    size_t size() const;
    mix_addr(std::initializer_list<addr_gen> arg);
};

class seq_order_gen: public order_gen{
    public:
    size_t operator[](size_t i) const { return i; }
};

class thrash_order_gen: public order_gen{
    size_t size;
    public:
    size_t operator[](size_t i) const;
    thrash_order_gen(size_t size) { this->size = size; };
};

class rand_order_gen: public order_gen{
    size_t size;
    size_t *order;
    public:
    size_t operator[](size_t i) const { return order[i]; }
    rand_order_gen(size_t size);
    ~rand_order_gen();
};

void fill_buf(const addr_gen &addr, const order_gen &order);

size_t fill_buf(void *buf, void order_gen(size_t*, size_t), size_t size, size_t stride, size_t offset);

void seq_order(size_t* order, size_t size);

void rand_order(size_t* order, size_t size);

void thrash_order(size_t* order, size_t size);

void* pointer_chasing_reverse_16(void *begin, size_t iter);

void* pointer_chasing_16(void *begin, size_t iter);

void* pointer_chasing_w_16(void *begin, size_t iter);

std::pair<void*, void*> pointer_chasing_16(void *a, void *b, size_t iter);

size_t next_size(size_t cur, size_t step);